//
//  YZMStockSearchService.m
//  YZMicroStock
//
//  Created by wangminhong on 16/4/8.
//  Copyright © 2016年 cqjr. All rights reserved.
//

#import "YZMStockSearchService.h"
#import "YZMStockItemModel.h"
#import "YZMAllStockPacket.h"
#import "YZClient.h"
#import "YZMStockInfo.h"
#import "YZMSeverTimeService.h"

#import <NSDate+DateTools.h>
#import <CoreData/CoreData.h>

static NSString *const sYZMStockListVersionDefault = @"YZMStockListVersionDefault";

@interface YZMStockSearchService()

@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, strong) NSManagedObjectModel *managedObjectModel;
@property (nonatomic, strong) NSPersistentStoreCoordinator *persistentStoreCoordinator;
@property (nonatomic, strong) NSDate *versionDate;
@property (nonatomic, strong) NSOperationQueue *operationQueue;
@property (nonatomic, assign) BOOL ready;
@property (nonatomic, strong) NSString *historyCodes;

@end

@implementation YZMStockSearchService

@synthesize historyCodes = _historyCodes;

+ (instancetype)sharedService
{
    static YZMStockSearchService *sInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sInstance = [[self alloc] init];;
    });
    
    return sInstance;
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        self.versionDate = [[NSUserDefaults standardUserDefaults] objectForKey:sYZMStockListVersionDefault];
        self.operationQueue = [[NSOperationQueue alloc] init];
        self.operationQueue.maxConcurrentOperationCount = 1;
        __weak typeof(&*self) safeSelf = self;
        [self.operationQueue addOperationWithBlock:^{
            [safeSelf managedObjectContext];
            safeSelf.ready = YES;
        }];

        [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(noticeForResignActive:) name: UIApplicationWillResignActiveNotification object: nil];
    }
    return self;
}

- (void)noticeForResignActive:(id)notice{
    
    [self saveContext];
}

- (void)checkIfNeedUpdateStocks{
    
    NSDate *serverdate = [YZMSeverTimeService sharedService].severDate;
    if (self.versionDate && [self.versionDate isSameDay:serverdate] && (self.versionDate.hour >9 || (self.versionDate.hour ==9 && self.versionDate.minute >= 17))) {
        
        //同一天，且上次更新时间 大于9点16分，不需要更新
        return;
    }
    
    [self.operationQueue addOperationWithBlock:^{
        
        [self fetchAllStockFromNetwork];
    }];
}

- (void)fetchAllStockFromNetwork
{

    [YZClient qt_getAllStocksWithVersion:nil success:^(NSURLResponse *response, id responseObject) {
        
        YZGeneralResultModel *topModel = responseObject;
        if (topModel.success) {
            
            YZMAllStockPacket *packet = topModel.data;
            __weak typeof(&*self) safeSelf = self;
            [safeSelf updateNativeStoreageWithArray: packet.stocks];
            if (packet.versionDate) {
                [[NSUserDefaults standardUserDefaults] setObject:packet.versionDate forKey:sYZMStockListVersionDefault];
                safeSelf.versionDate = packet.versionDate;
            }
        }
        
    } failure:nil];
}

- (void)updateNativeStoreageWithArray: (NSArray *)array
{
    if (array.count == 0) {
        
        return;
    }
    
    for (YZMStockItemModel *item in array) {
        if (item.code.length == 0) {
            continue;
        }
        [self.operationQueue addOperationWithBlock:^{
            YZMStockInfo *stockInfo = [self fecthStockWithStockCode: item.code];
            if (!stockInfo) {
                stockInfo = [NSEntityDescription insertNewObjectForEntityForName:@"StockInfo"
                                                          inManagedObjectContext: self.managedObjectContext];
            }
            if (stockInfo) {
                stockInfo.code = item.code;
                stockInfo.name = item.name;
                stockInfo.pinyin = [item.pinyin uppercaseString];
            }
        }];
    }
    [self saveContext];
}

- (YZMStockInfo *)fecthStockWithStockCode: (NSString *)stockCode
{
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"StockInfo"];
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"code == %@", stockCode];
    request.predicate = predicate;
    NSError *error = nil;
    NSArray *results = [self.managedObjectContext executeFetchRequest: request error: &error];
    if (results.count == 0) {
        return nil;
    }
    else
    {
        return results[0];
    }
}

- (void)fecthStocksWithInput:(NSString *)inputStr result: (void (^)(NSArray *))result
{
    if (!self.ready || result == nil) {
        return ;
    }
    inputStr = inputStr.uppercaseString;
    [self.operationQueue cancelAllOperations];
    [self.operationQueue addOperationWithBlock:^{
        NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"StockInfo"];
        request.fetchLimit = 20;
        NSSortDescriptor *sortDesc  = [NSSortDescriptor sortDescriptorWithKey: @"code" ascending: YES];
        request.sortDescriptors = @[sortDesc];
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(code CONTAINS %@) OR (pinyin CONTAINS %@) OR (name CONTAINS %@)", inputStr, inputStr, inputStr];
        request.predicate = predicate;
        NSError *error = nil;
        NSArray *results = [self.managedObjectContext executeFetchRequest: request error: &error];
        if (results.count == 0) {
            results = nil;
        }
        dispatch_async(dispatch_get_main_queue(), ^{
            result(results);
        });
    }];
}


#define sYZMHISTORYLIMIT 10

- (void)appendHistoryWithCode: (NSString *)code
{
    if (code.length == 0) {
        return;
    }
    NSMutableArray *array = [self.historyCodes componentsSeparatedByString: @","].mutableCopy;
    if (array == nil) {
        array = @[].mutableCopy;
    }
    NSInteger found = [array indexOfObject: code];
    if (found != NSNotFound) {
        [array removeObjectAtIndex: found];
    }
    [array insertObject: code atIndex: 0];
    //limit
    if (array.count > sYZMHISTORYLIMIT) {
        [array removeObjectsInRange: NSMakeRange(sYZMHISTORYLIMIT, array.count-sYZMHISTORYLIMIT)];
    }
    NSString *result = [array componentsJoinedByString:@","];
    self.historyCodes = result;
}

- (void)fecthHistoryResult:(void (^)(NSArray *))result
{
    if (!self.ready || result == nil) {
        return;
    }
    [self.operationQueue addOperationWithBlock:^{
        
        NSMutableArray *tempArray = [NSMutableArray array];
        NSArray *array = [self.historyCodes componentsSeparatedByString: @","];
        for (NSString *str in  array) {
            if (str.length > 0) {
                YZMStockInfo *stock = [self fecthStockWithStockCode: str];
                if (stock) {
                    [tempArray addObject: stock];
                }
            }
        }
        dispatch_async(dispatch_get_main_queue(), ^{
            result(tempArray);
        });
    }];
}

- (void)clearHistory
{
    self.historyCodes = nil;
}

#pragma mark -- override

#define sYZMStockSearchHistoryDefault @"YZMStockSearchHistoryDefault"

- (NSString *)historyCodes
{
    if (_historyCodes == nil) {
        _historyCodes = [[NSUserDefaults standardUserDefaults] objectForKey: sYZMStockSearchHistoryDefault];
    }
    return _historyCodes;
}

- (void)setHistoryCodes:(NSString *)historyCodes
{
    if (_historyCodes != historyCodes) {
        _historyCodes = historyCodes;
        if (_historyCodes == nil) {
            [[NSUserDefaults standardUserDefaults] removeObjectForKey: sYZMStockSearchHistoryDefault];
        }
        else
        {
            [[NSUserDefaults standardUserDefaults] setObject: _historyCodes forKey: sYZMStockSearchHistoryDefault];
        }
    }
}


#pragma mark - Core Data stack

- (NSURL *)applicationDocumentsDirectory {
    
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
    
    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }
    
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"StockStorage.sqlite"];
    NSError *error = nil;
    NSString *failureReason = @"There was an error creating or loading the application's saved data.";
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
        // Report any error we got.
        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        dict[NSLocalizedDescriptionKey] = @"Failed to initialize the application's saved data";
        dict[NSLocalizedFailureReasonErrorKey] = failureReason;
        dict[NSUnderlyingErrorKey] = error;
        error = [NSError errorWithDomain:@"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
        // Replace this with code to handle the error appropriately.
        // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }
    
    return _persistentStoreCoordinator;
}

- (NSManagedObjectModel *)managedObjectModel {
    
    if (_managedObjectModel != nil) {
        return _managedObjectModel;
    }
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"StockStorage" withExtension:@"momd"];
    _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    return _managedObjectModel;
}


- (NSManagedObjectContext *)managedObjectContext {
    
    if (_managedObjectContext != nil) {
        return _managedObjectContext;
    }
    
    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (!coordinator) {
        return nil;
    }
    _managedObjectContext = [[NSManagedObjectContext alloc] init];
    [_managedObjectContext setPersistentStoreCoordinator:coordinator];
    return _managedObjectContext;
}

#pragma mark - Core Data Saving support

- (void)saveContext {
    
    [self.operationQueue addOperationWithBlock:^{
        NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
        if (managedObjectContext != nil) {
            NSError *error = nil;
            if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
                // Replace this implementation with code to handle the error appropriately.
                // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
                abort();
            }
        }
    }];
}


@end
